﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Jayden.Dll.Cards.Poker.Enums;
using System.Threading;
using System.IO;

namespace Jayden.Dll.Cards.Poker
{
	public abstract class PokerDealer
	{
		private PokerTable m_Table;

		protected PokerPot m_Pot;
		protected PokerStreetType m_Street;
		protected DateTime m_HandDateTime;
		private bool m_Running = false;
		private Thread m_Thread = null;

		public Thread Thread { get { return m_Thread; } }
		public PokerStreetType Street { get { return m_Street; } }
		public DateTime HandDateTime { get { return m_HandDateTime; } }

		public PokerPot Pot { get { return m_Pot; } }
		public PokerTable Table
		{
			get { return m_Table; }
			set
			{
				if (m_Table == value)
					return;
				if (value != null && !CanDeal(value.Configuration))
					throw new Exception("Invalid dealer for table.");
				if (m_Table != null)
					m_Table.Dealer = null;
				m_Table = value;
				if (m_Table != null)
					m_Table.Dealer = this;
			}
		}

		public PokerCurrency Currency { get { return Table.Currency; } }

		public PokerGameConfiguration Configuration { get { return Table.Configuration; } }

		public bool Running { get { return m_Running; } }
		public ulong Ante { get { return Table.Ante; } }
		public ulong SmallBlind { get { return Table.SmallBlind; } }
		public ulong BigBlind { get { return Table.BigBlind; } }

		public PokerType Type { get { return Table.Type; } }
		public PokerLimit Limit { get { return Table.Limit; } }

		public abstract bool CanDeal(PokerGameConfiguration config);
		public abstract bool Busy { get; }
		public abstract bool CanStartHand { get; }
		public abstract void Reset(Exception e);
		public abstract void NextHand();
		public abstract void PlayerShowCards(string playerName, CardList cards);
		public abstract int FirstIdlePlayerIndex { get; }

		private bool m_Stopping = false;
		public void Start()
		{
			if (m_Thread != null)
				throw new Exception("thread is already created.");
			m_Thread = new Thread(Run);
			m_Thread.Start();
		}
		public void Stop()
		{
			m_Stopping = true;
		}
		public void Join()
		{
			if (m_Thread == null)
				return;
			m_Thread.Join();
		}

		public void Run()
		{
			if (m_Running)
				throw new Exception("already running.");
			if(m_Table == null)
				throw new Exception("not assigned to a table.");
			m_Running = true;
			m_Stopping = false;
			while (!m_Stopping && !Configuration.Finished && !Table.Closed)
			{
				try
				{
					if (!CanStartHand)
						Thread.Sleep(5000);
					else
						NextHand();
				}
				catch(Exception e)
				{
					Reset(e);
				}
			}
			m_Running = false;
			lock (this)
			{
				Monitor.PulseAll(this);
			}
			m_Thread = null;
		}


		protected void Log(string format, params object[] p)
		{
			// todo
		}
	}
}
